﻿using System.IO;
using System.Windows.Forms;
using System.Diagnostics;

namespace PolePosition.v3.GoogleEarth
{
    public partial class MapControl : UserControl
    {
        public bool MapStarted
        {
            get
            {
                return true;
            }
        }

        public void StartMap()
        {
            // do nothing
        }

        public void StopMap()
        {
            // do nothing
        }

        public void ResetPosition()
        {
            // do nothing
        }

        public void LoadKmlFromString(string kml)
        {
            if (string.IsNullOrEmpty(kml))
                return;

            // write to temp file

            string _Path = Path.GetDirectoryName(Application.ExecutablePath) + @"\PolePosition.Kml";
            //string _Path = @"c:\PolePosition.Kml";
            File.WriteAllText(_Path, kml);

            // load temp file

            LoadKmlFromFile(_Path);
        }

        public void LoadKmlFromFile(string path)
        {
            if (!File.Exists(path))
                throw new FileNotFoundException(path);

            // start kml

            var _Process = new Process();

            _Process.StartInfo.FileName = path;
            _Process.Start();
        }

        /*

        #region Win API

        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static IntPtr GetParent(
            IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern int SetParent(
            int hWndChild,
            int hWndParent);

        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(
            int hWnd,
            int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool PostMessage(
            int hWnd,
            uint Msg,
            int wParam,
            int lParam);

        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        private static extern bool SetWindowPos(
            int hWnd,
            int hWndInsertAfter,
            int X,
            int Y,
            int cx,
            int cy,
            uint uFlags);

        [DllImport("user32.dll")]
        private static extern int SendMessage(
            int hWnd,
            uint Msg,
            int wParam,
            int lParam);

        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static bool MoveWindow(
            IntPtr hWnd,
            int X,
            int Y,
            int nWidth,
            int nHeight,
            bool bRepaint);

        private const int HWND_TOP = 0x0;
        private const int WM_COMMAND = 0x0112;
        private const int WM_QT_PAINT = 0xC2DC;
        private const int WM_PAINT = 0x000F;
        private const int WM_SIZE = 0x0005;
        private const int SWP_FRAMECHANGED = 0x0020;

        #endregion

        public MapControl()
        {
            InitializeComponent();
            MapStarted = false;
        }

        #region Properties

        private IntPtr m_GetRenderHwndParent;
        private ApplicationGEClass m_GoogleEarth;
        private ApplicationGEClass GoogleEarth
        {
            get
            {
                //if (m_GoogleEarth != null && m_GoogleEarth.IsInitialized() != 1)
                //        throw new Exception("Google Earth is not initialized.");
                return m_GoogleEarth;
            }
            set
            {
                m_GoogleEarth = value;
            }
        }

        private bool m_MapStarted;
        /// <summary>
        /// Indicates if the map has already been started
        /// </summary>
        public bool MapStarted
        {
            get
            {
                if (m_MapStarted)
                    return true;
                if (GoogleEarth != null)
                    return true;
                return false;
            }
            private set
            {
                m_MapStarted = value;
            }
        }

        /// <summary>
        /// Gets the current viewing location on the map
        /// </summary>
        public MapPosition CurrentPosition
        {
            get
            {
                if (!MapStarted)
                    StartMap();

                CameraInfoGE _Camera = GoogleEarth.GetCamera(1);
                return new MapPosition
                {
                    Altitude = _Camera.FocusPointAltitude,
                    Latitude = _Camera.FocusPointLatitude,
                    Longitude = _Camera.FocusPointLongitude,
                    AltitudeMode = _Camera.FocusPointAltitudeMode,
                    Range = _Camera.Range,
                    Tilt = _Camera.Tilt
                };
            }
        }
        
        #endregion

        /// <summary>
        /// Fires after the map has started
        /// </summary>
        public event EventHandler OnMapStarted;
        public void RaiseOnMapStarted(EventArgs e)
        {
            if (OnMapStarted != null)
                OnMapStarted(this, e);
        }

        /// <summary>
        /// Turn the map on - this can be a long process for the application to start up
        /// </summary>
        public void StartMap()
        {
            if (IsDesignMode(this))
                return;
            if (MapStarted)
                return;
            MapStarted = true;
            GoogleEarth = new ApplicationGEClass();

            // Start and setup map

            ShowWindowAsync(GoogleEarth.GetMainHwnd(), 0);
            SetParent(GoogleEarth.GetRenderHwnd(), panelGeContainer.Handle.ToInt32());

            IntPtr _GetRenderHwnd;
            _GetRenderHwnd = (IntPtr)GoogleEarth.GetRenderHwnd();
            m_GetRenderHwndParent = GetParent(_GetRenderHwnd);

            IntPtr _GetMainHwnd;
            _GetMainHwnd = (IntPtr)GoogleEarth.GetMainHwnd();

            //SetParent((int)_GetMainHwnd, panelGeContainer.Handle.ToInt32());

            //MoveWindow(_GetRenderHwnd, 0, 0, this.Width, this.Height, true);
            //SetParent((int)_GetRenderHwnd, this.Handle.ToInt32());

            this.Resize += delegate(object sender, EventArgs e)
                {
                    ResizeMap();
                };
            ResizeMap();

            RaiseOnMapStarted(new EventArgs());
        }

        /// <summary>
        /// Fires after the map has stopped
        /// </summary>
        public event EventHandler OnMapStopped;
        private void RaiseOnMapStopped(EventArgs e)
        {
            MapStarted = false;
            if (OnMapStopped != null)
                OnMapStopped(this, e);
        }

        /// <summary>
        /// Turn the map off - this can be a long process for the application to shut down
        /// </summary>
        public void StopMap()
        {
            if (!MapStarted)
                return;

            if (m_GetRenderHwndParent == (IntPtr)0)
                return;

            try
            {
                int SC_CLOSE = 0xF060;
                uint WM_CLOSE = 0x10;
                uint WM_SYSCOMMAND = 0x0112;

                HideBalloon();
                GoogleEarth.Logout();

                PostMessage(GoogleEarth.GetRenderHwnd(), WM_CLOSE, 0, 0);
                PostMessage(GoogleEarth.GetMainHwnd(), WM_CLOSE, 0, 0);
                SendMessage(GoogleEarth.GetMainHwnd(), WM_SYSCOMMAND, SC_CLOSE, 0);
            }
            catch
            {
                // what to do?
            }
            finally
            {
                // if all else fails, kill it

                foreach (Process _Process in Process.GetProcessesByName("googleearth.exe"))
                    _Process.Kill();

                // this will prevent it from being reloaded

                m_GetRenderHwndParent = (IntPtr)0;
                RaiseOnMapStopped(new EventArgs());
            }
        }

        /// <summary>
        /// Fires after the map has been resized
        /// </summary>
        public event EventHandler OnMapResized;
        private void RaiseOnMapResized(EventArgs e)
        {
            if (OnMapResized != null)
                OnMapResized(this, e);
        }
        private void ResizeMap()
        {
            if ((IntPtr)GoogleEarth.GetRenderHwnd() == (IntPtr)0)
                return;
            MoveWindow((IntPtr)GoogleEarth.GetRenderHwnd(), 0, 0, this.Width, this.Height, true);
            SetWindowPos(GoogleEarth.GetRenderHwnd(), HWND_TOP, 0, 0, this.Width, this.Height, SWP_FRAMECHANGED);
            RaiseOnMapResized(new EventArgs());

            return;

            if (!MapStarted)
                return;

            SendMessage(GoogleEarth.GetMainHwnd(), WM_COMMAND, WM_PAINT, 0);
            PostMessage(GoogleEarth.GetMainHwnd(), WM_QT_PAINT, 0, 0);
            SetWindowPos(GoogleEarth.GetMainHwnd(), HWND_TOP, 0, 0, this.Width, this.Height, SWP_FRAMECHANGED);
            // SetWindowPos(GoogleEarth.GetRenderHwnd(), HWND_TOP, 0, 0, this.Width, this.Height, SWP_FRAMECHANGED);
            SendMessage(GoogleEarth.GetRenderHwnd(), WM_COMMAND, WM_SIZE, 0);

            //MoveWindow((IntPtr)GoogleEarth.GetRenderHwnd(), 0, 0, this.Width, this.Height, true);
            
            RaiseOnMapResized(new EventArgs());
        }

        /// <summary>
        /// Fires after the KML has been loaded
        /// </summary>
        public event EventHandler OnKmlLoaded;
        private void RaiseOnKmlLoaded(EventArgs e)
        {
            if (OnKmlLoaded != null)
                OnKmlLoaded(this, e);
        }

        /// <summary>
        /// Load a KML to the map; KML with the same NAME will be replaced
        /// </summary>
        /// <param name="path"></param>
        public void LoadKmlFromFile(string path)
        {
            if (!MapStarted)
                StartMap();

            // check the file

            if (!System.IO.File.Exists(path))
                throw new System.IO.FileNotFoundException(path);

            // okay, do it

            GoogleEarth.OpenKmlFile(path, 1);
            RaiseOnKmlLoaded(new EventArgs());
        }

        /// <summary>
        /// Load a KML to the map; KML with the same NAME will be replaced
        /// </summary>
        /// <param name="kml"></param>
        public void LoadKmlFromString(string kml)
        {
            if (!MapStarted)
                StartMap();

            // is there Kml to load?

            if (string.IsNullOrEmpty(kml))
                return;
            string _Path = @"c:\temp.Kml";
            System.IO.File.WriteAllText(_Path, kml);
            LoadKmlFromFile(_Path);

            RaiseOnKmlLoaded(new EventArgs());
        }

        /// <summary>
        /// If a balloon is visible, make it invisible (there are painting reasons for this)
        /// </summary>
        public void HideBalloon()
        {
            if (!MapStarted)
                StartMap();

            GoogleEarth.HideDescriptionBalloons();
        }

        /// <summary>
        /// Change the current viewing location to a view of North America
        /// </summary>
        public void ResetPosition()
        {
            if (!MapStarted)
                StartMap();

            // center over n. america

            FlyTo(new MapPosition()
            {
                Altitude = 255.43095188550069F,
                Latitude = 36.955780035889667F,
                Longitude = -93.6590360982408F,
                Range = 10000000
            });
        }

        /// <summary>
        /// Change the current viewing location to the specified coordinates
        /// </summary>
        /// <param name="latitude"></param>
        /// <param name="longitude"></param>
        /// <param name="altitude"></param>
        public void FlyTo(double latitude, double longitude, double? altitude)
        {
            FlyTo(new MapPosition()
            {
                 Altitude = altitude ==  null ? 10000 : (double)altitude,
                 Latitude = latitude,
                 Longitude = longitude,
                 AltitudeMode = 0
            });
        }

        /// <summary>
        /// Change the current viewing location to the specified coordinates
        /// </summary>
        /// <param name="position"></param>
        public void FlyTo(MapPosition position)
        {
            if (!MapStarted)
                StartMap();

            GoogleEarth.SetCameraParams(
                position.Latitude, 
                position.Longitude, 
                position.Altitude < 7000 ? 10000 : position.Altitude,
                position.AltitudeMode == 0 ? AltitudeModeGE.RelativeToGroundAltitudeGE : position.AltitudeMode,
                (double)(position.Range == null ? 10000000 : position.Range),
                (double)(position.Tilt == null ? 0 : position.Tilt),
                0, 1);
        }

        public static bool IsDesignMode(Control c)
        {
            if (c == null)
            {
                return false;
            }
            if (c.Created)
            {
                if (!((c.Site == null)) && c.Site.DesignMode)
                {
                    return true;
                }
            }
            else
            {
                if ((System.Reflection.Assembly.GetEntryAssembly() == null))
                {
                    return true;
                }
            }
            return IsDesignMode(c.Parent);
        }

         */
    }
}
